using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace Dida.Dxml
{
	static class ErrorHandling
	{
		static Dictionary<Type,string> defTypeNames = new Dictionary<Type,string>();
		static ErrorHandling()
		{
			defTypeNames.Add(typeof(float),"float");
			defTypeNames.Add(typeof(int),"int");
			defTypeNames.Add(typeof(string),"string");
			defTypeNames.Add(typeof(bool),"bool");
		}

		public static string GetReadableTypeName(Type type)
		{
			StringBuilder ret = new StringBuilder();
			GetReadableTypeNameImpl(type,ret);
			return ret.ToString();
		}

		private static void GetReadableTypeNameImpl(Type type, StringBuilder str)
		{
			if (type.IsGenericType)
			{
				Type genTypeDef = type.GetGenericTypeDefinition();
				str.Append(GetTypeName(genTypeDef));
				
				str.Append('<');				
				Type[] genericArgs = type.GetGenericArguments();
				for(int i = 0;i < genericArgs.Length;i++)
				{
					GetReadableTypeNameImpl(genericArgs[i],str);
					if (i == genericArgs.Length - 1)
						str.Append('>');
					else
						str.Append(", ");
				}
			}
			else
			{
				str.Append(GetTypeName(type));
			}

		}

		private static string GetTypeName(Type type)
		{
			string ret;
			if (defTypeNames.TryGetValue(type, out ret))
				return ret;
			else if (type.IsGenericType)
			{
				string name = type.Name;
				int tickPos = name.LastIndexOf('`');
				return name.Substring(0, tickPos);
			}
			else
			{
				return type.Name;
			}
		}
	}

	public class IncompatibleReferenceException : XmlReaderException
	{
		string refName;
		Type refType;
		Type expectedType;
		XmlPositionMarker pos;

		internal IncompatibleReferenceException(string refName, Type refType,
			Type expectedType, XmlPositionMarker pos)
			: base(GetMessage(refName,refType,expectedType), pos)
		{
			this.refName = refName;
			this.refType = refType;
			this.expectedType = expectedType;
			this.pos = pos;
		}

		private static string GetMessage(string refName, Type refType, Type expectedType)
		{
			return "The object \"" + refName + "\" (which is of type \"" +
				ErrorHandling.GetReadableTypeName(refType) +
				"\") isn't compatible with the expected type \"" +
				ErrorHandling.GetReadableTypeName(expectedType) + "\".";
		}
	}
}